.text
.section .rodata
.align 3
.LC0:
        .string "Hello"
        .align  3
.LC1:
        .string "str1 is %s\n"
        .align  3
.LC2:
        .string "str2 is %s\n"
        .align  3
.LC3:
        .string "str3 is %s\n"

.text
.align 2
.globl main
.type main, @function

main:
    addi sp, sp, -48
    // 把返回地址ra寄存器存到堆栈中
    sd ra, 40(sp)
    // s0:frame pointer相当于bp，存到堆栈中
    // 以便将来恢复
    sd s0, 32(sp)
    // 把基准寄存器s0存成原来的栈顶，即+48之前的栈顶
    addi s0, sp, 48
    // li是加载立即数，即load immediately
    li a5, 1819041792
    // 可能是因为li指令加载不完所有的字符，所以需要再来一个加法
    // 最终的结果就是a5里面存上了Hello这几个字符
    addi a5, a5, 1352
    // 这里为什么是sw?看下面两行就知道了，其实这里只处理Hell，o额外再处理
    sw a5, -32(s0)
    li a5, 111
    sb a5, -28(s0)
    // 这样-32(s0)往后的5个字节就变成了:Hello, str1就是-32(s0)

    li a5, 1819041792
    addi a5, a5, 1352
    sw a5, -40(s0)
    li a5, 111
    sb a5, -36(s0)
    // 这样-40(s0)往后的5个字节就变成了:Hello, str1就是-40(s0)
    // 从上面的代码我们可以看到，riscv对str1和str2的处理方式一模一样，所以不存在没有结束符的问题
    // 但是x86就存在
    // 另外riscv是8字节对齐的，x86不是，所以x86比较省内存

    lui a5, %hi(.LC0)
    addi a5, a5, %lo(.LC0)
    sd a5, -24(s0)
    // 以上3行，是把str3的值初始化，str3就是-24(s0)

    // 获得str1的地址
    addi a5, s0, -32
    // 把str1的地址当成第一个参数
    mv a1, a5
    lui a5, %hi(.LC1)
    addi a0, a5, %lo(.LC1)
    call printf

    // 获取str2的地址
    addi a5, s0, -40
    mv a1, a5
    lui a5, %hi(.LC1)
    addi a0, a5, %lo(.LC1)
    call printf

    ld a1, -24(s0)
    lui a5, %hi(.LC2)
    addi a0, a5, %lo(.LC2)
    call printf

    // 返回值设置为0
    li a5, 0
    mv a0, a5
    // 恢复寄存器
    ld ra, 40(sp)
    ld s0, 32(sp)
    addi sp, sp, 48
    // 跳转到返回地址，相当于ret
    jr ra

